#ifndef CAEN_module_h
#define CAEN_module_h

#include <sys/types.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>

#include "vme_sis.h"
#include "VmeModule.h"
#include "IOError.h"
#include "EventStruct.h"
#include "stringutil.h"


/*----------------------------------------------------------------------------
Integration of the CAEN_module by CAEN to Dackel 20070404, Alex Kaplan
----------------------------------------------------------------------------*/

class CAEN_module : public VmeModule
{
 public:
		
    // #########################
    // Register Adresses
    // #########################
    
	const static u_int16_t OUTPUT_BUFFER              =0x0000;
    //const static u_int16_t OUTPUT_BUFFER_LENGTH       =0x07cf;		
    const static u_int16_t FIRMWARE_REVISION          =0x1000;
    const static u_int16_t GEO_ADDRESS_REGISTER       =0x1002;
    const static u_int16_t MCST_CBLT_ADDRESS_REGISTER =0x1004;
    const static u_int16_t BITSET_1                   =0x1006;
    const static u_int16_t BITCLEAR_1                 =0x1008;
    const static u_int16_t INTERRUPT_LEVEL            =0x100a;
    const static u_int16_t INTERRUPT_VECTOR           =0x100c;
    const static u_int16_t STATUS_REGISTER_1          =0x100e;
    const static u_int16_t CONTROL_REGISTER_1         =0x1010;
    const static u_int16_t ADER_HIGH                  =0x1012;
    const static u_int16_t ADER_LOW                   =0x1014;
    const static u_int16_t SINGLE_SHOT_RESET          =0x1016;
    const static u_int16_t MCST_CBLT_CTRL             =0x101a;
    const static u_int16_t EVENT_TRIGGER_REGISTER     =0x1020;
    const static u_int16_t STATUS_REGISTER_2          =0x1022;
    const static u_int16_t EVENT_COUNTER_L            =0x1024;
    const static u_int16_t EVENT_COUNTER_H            =0x1026;
    const static u_int16_t INCREMENT_EVENT            =0x1028;
    const static u_int16_t INCREMENT_OFFSET           =0x102a;
    const static u_int16_t LOAD_TEST_REGISTER         =0x102c;
    const static u_int16_t FAST_CLEAR_WINDOW_REGISTER =0x102e;
    const static u_int16_t BITSET_2                   =0x1032;
    const static u_int16_t BITCLEAR_2                 =0x1034;
    const static u_int16_t W_MEMORY_TEST_ADDRESS      =0x1036;
    const static u_int16_t MEMORY_TEST_WORD_HIGH      =0x1038;
    const static u_int16_t MEMORY_TEST_WORD_LOW       =0x103a;
    const static u_int16_t CRATE_SELECT               =0x103c;
    const static u_int16_t TEST_WRITE                 =0x103e;
    const static u_int16_t EVENT_COUNTER_RESET        =0x1040;
    //const static u_int16_t IPED                       =0x1060;
    const static u_int16_t R_TEST_ADDRESS             =0x1064;
    const static u_int16_t SW_COMM                    =0x1068;
    //const static u_int16_t SLIDE_CONST                =0x106A;
    const static u_int16_t AAD                        =0x1070;
    const static u_int16_t BAD                        =0x1072;
    const static u_int16_t THRESHOLD_START            =0x1080;

    //-- bit patterns for output buffer data
    const static u_int32_t MEM_CHANNEL_MASK           =0x00003f00;
    const static u_int16_t MEM_CHANNEL_SHIFT          =8;
    const static u_int32_t VALID_DATUM                =0x00000000;
	const static u_int32_t HEADER_MASK                =0x0300C000;
    const static u_int32_t IS_HEADER                  =0x02000000;
	const static u_int32_t GEO_MASK		              =0xf8000000;
	const static u_int32_t GEO_SHIFT	              =27;
	const static u_int32_t CRATE_MASK	              =0x00ff0000;
	const static u_int32_t CRATE_SHIFT	              =16;
    const static u_int32_t IS_EOB                     =0x04000000;
    const static u_int32_t EOB_EVCOUNT_MASK           =0x00ffffff;

    // #########################
    // Bit Set/Clear 1 Register.
    // #########################
    // Bit pattern. If bit is set, the things in the comment happen, if bit is
    // not set (0), they do not happen.

    // Only these bits are allowed to be modified
    const static u_int16_t BITSET_1_ALLOWED_BITS       =0x0098;
    // There was a bus error meaningful in BLT/CBLT modes only
    const static u_int16_t BITSET_1_BERR_FLAG          =0x0008;
    // Select address via  internal ADDR registers
    const static u_int16_t BITSET_1_SELECT_ADDRESS     =0x0010;
    // Software reset status
    const static u_int16_t BITSET_1_SOFTWARE_RESET     =0x0080;

    // #########################
    // Bit Set/Clear 2 Register.
    // #########################
    // Bit pattern. If bit is set, the things in the comment happen, if bit is
    // not set (0), they do not happen.

    // Only these bits are allowed to be modified
    const static u_int16_t BITSET_2_ALLOWED_BITS          =0x78ff;
    // Random memory access test mode
    const static u_int16_t BITSET_2_TEST_MEMORY_MODE      =0x0001;
    // ADC off, no conversion
    const static u_int16_t BITSET_2_OFFLINE               =0x0002;
    // Clear data, counter...
    const static u_int16_t BITSET_2_CLEAR_DATA_BIT        =0x0004;
    // Store overrange data
    const static u_int16_t BITSET_2_OVER_RANGE_ENABLED    =0x0008;
    // Store below threshold data
    const static u_int16_t BITSET_2_LOW_THRESHOLD_ENABLED =0x0010;
	// Store only valid data (TDC in common stop mode)
	const static u_int16_t BITSET_2_VALID_ENABLED		  =0x0020;
    // Acquisition test mode active
    const static u_int16_t BITSET_2_TEST_ACQ_MODE         =0x0040;
    // Sliding scale enabled
    const static u_int16_t BITSET_2_SLIDE_ENABLE          =0x0080;
    //Treshold is THRESHOLD value * 16, if bit is not set,
    //Treshold is THRESHOLD value * 2
    const static u_int16_t BITSET_2_STEP_THRESHOLD        =0x0080;
	// TDC: common mode is 'common start' if eq 0, 'common stop' if eq 1
	const static u_int16_t BITSET_2_COMMON_MODE 		  =0x0100;
    // readout pointer is incremented automaticly
    const static u_int16_t BITSET_2_AUTO_INCREMENT_ENABLE =0x0800;
    // Header written also if there are no accepted cannels
    const static u_int16_t BITSET_2_EMPTY_ENABLE          =0x1000;
    // Subtraction section of sliding scale disabled (only for test!)
    const static u_int16_t BITSET_2_SLIDE_SUBTR_DISABLE   =0x2000;
    // Event counter incremented on all triggers
    const static u_int16_t BITSET_2_ALL_TRIGGERS          =0x4000;
 
    //bits used in the tresholds memory registers
    const static u_int16_t THRESHOLD_MASK                 =0x00ff;
    const static u_int16_t CH_DISABLE_MASK                =0x0100;

    //fast clear stuff
    const static u_int16_t FAST_CLEAR_WINDOW_MASK         =0x03ff;
    const static u_int16_t FAST_CLEAR_WINDOW_MAXWIDTH     =0x03f0;

    // Buffer is empty.
    const static u_int16_t STATUS_REGISTER_2_BUFFER_EMPTY =0x0002; 
    // Buffer is full.
    const static u_int16_t STATUS_REGISTER_2_BUFFER_FULL  =0x0004;


    //constructor / destructor
    CAEN_module( int handle, u_int32_t addr );
    virtual ~CAEN_module() {};

	virtual u_int32_t GetNChannels();
    
	u_int32_t GetEventCounter();

    // Set bits of Bit1 register. The function accesses only bits that are
    // allowed to be changed.
    void SetBit1Pattern(u_int16_t pattern);

    // Clears bits of Bit1 register. The function accesses only bits that are
    // allowed to be changed.
    void ClearBit1Pattern(u_int16_t pattern);

    // Set bits of Bit2 register. The function accesses only bits that are
    // allowed to be changed.
	void SetBit2Pattern(u_int16_t pattern);

    // Clears bits of Bit2 register. The function accesses only bits that are
    // allowed to be changed.
    void ClearBit2Pattern(u_int16_t pattern);

    // Performs a software Reset
    void SoftwareReset();

    void EnableChannel(u_int16_t ch);
    void DisableChannel(u_int16_t ch);

    void SetThreshold(u_int16_t ch, u_int16_t thr);

    void DefineChannelBehaviour(u_int32_t Pattern);
    void DefineChannelBehaviour(u_int32_t Pattern, u_int16_t Threshold);

    void CountOnlyValidEvents();
    void CountAllEvents();

    u_int16_t GetFastClearWindow();
    void SetFastClearWindow(u_int16_t width);

    void ClearData();
    void ClearEventCounter();

    bool BufferEmpty();
    bool BufferFull();

    u_int16_t GetStatus1();
    u_int16_t GetStatus2();
};

#endif
